#include "zObjectShader.hpp"
#include "zRenderScript.hpp"

namespace zzz{

bool ShaderLoader::LoadShaderFile( const char* vertexFile, const char* fragmentFile, Shader *o)
{
  bool ret=o->LoadVertexFile(vertexFile) && o->LoadFragmentFile(fragmentFile) && o->Link();
  return ret;
}

bool ShaderLoader::LoadShaderMemory( const char* vertexMem, const char* fragmentMem, Shader *o)
{
  bool ret=o->LoadVertexMemory(vertexMem) && o->LoadFragmentMemory(fragmentMem) && o->Link();
  return ret;
}

bool zObjectShader::LoadFromMemory(istringstream &iss, const string &path)
{
  Shader *shader=(Shader*)m_obj;
  shader->Clear();

  string FragmentShaderFilename="",VertexShaderFilename="";

  string buf;
  while(true)
  {
    iss>>buf;
    if (iss.fail()) break;
    ToLow(buf);
    if (buf=="v" || buf=="vert" || buf=="vertfile" || buf=="vertfilename")
    {
      iss>>buf;
      VertexShaderFilename=PathFile(path,buf);
    }
    else if (buf=="f" || buf=="frag" || buf=="fragfile" || buf=="fragfilename")
    {
      iss>>buf;
      FragmentShaderFilename=PathFile(path,buf);
    }
    else if (buf=="f1" || buf=="float1")
    {
      UniformParam tmp;
      tmp.type=UniformParam::F1;
      iss>>tmp.name;
      iss>>tmp.f1;
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="f2" || buf=="float2")
    {
      UniformParam tmp;
      tmp.type=UniformParam::F2;
      iss>>tmp.name;
      iss>>tmp.f2[0]>>tmp.f2[1];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="f3" || buf=="float3")
    {
      UniformParam tmp;
      tmp.type=UniformParam::F3;
      iss>>tmp.name;
      iss>>tmp.f3[0]>>tmp.f3[1]>>tmp.f3[2];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="f4" || buf=="float4")
    {
      UniformParam tmp;
      tmp.type=UniformParam::F4;
      iss>>tmp.name;
      iss>>tmp.f4[0]>>tmp.f4[1]>>tmp.f4[2]>>tmp.f4[3];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="i1" || buf=="int1")
    {
      UniformParam tmp;
      tmp.type=UniformParam::I1;
      iss>>tmp.name;
      iss>>tmp.i1;
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="i2" || buf=="int2")
    {
      UniformParam tmp;
      tmp.type=UniformParam::I2;
      iss>>tmp.name;
      iss>>tmp.i2[0]>>tmp.i2[1];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="i3" || buf=="int3")
    {
      UniformParam tmp;
      tmp.type=UniformParam::I3;
      iss>>tmp.name;
      iss>>tmp.i3[0]>>tmp.i3[1]>>tmp.i3[2];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="i4" || buf=="int4")
    {
      UniformParam tmp;
      tmp.type=UniformParam::I4;
      iss>>tmp.name;
      iss>>tmp.i4[0]>>tmp.i4[1]>>tmp.i4[2]>>tmp.i4[3];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="m2" || buf=="mat2" || buf=="matrix2" || buf=="mat2x2" || buf=="matrix2x2")
    {
      UniformParam tmp;
      tmp.type=UniformParam::M2;
      iss>>tmp.name;
      iss>>tmp.m2[0]>>tmp.m2[1]>>\
        tmp.m2[2]>>tmp.m2[3];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="m3" || buf=="mat3" || buf=="matrix3" || buf=="mat3x3" || buf=="matrix3x3")
    {
      UniformParam tmp;
      tmp.type=UniformParam::M3;
      iss>>tmp.name;
      iss>>tmp.m3[0]>>tmp.m3[1]>>tmp.m3[2]>>\
        tmp.m3[3]>>tmp.m3[4]>>tmp.m3[5]>>\
        tmp.m3[6]>>tmp.m3[7]>>tmp.m3[8];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="m4" || buf=="mat4" || buf=="matrix4" || buf=="mat4x4" || buf=="matrix4x4")
    {
      UniformParam tmp;
      tmp.type=UniformParam::M4;
      iss>>tmp.name;
      iss>>tmp.m4[0]>>tmp.m4[1]>>tmp.m4[2]>>tmp.m4[3]>>\
        tmp.m4[4]>>tmp.m4[5]>>tmp.m4[6]>>tmp.m4[7]>>\
        tmp.m4[8]>>tmp.m4[9]>>tmp.m4[10]>>tmp.m4[11]>>\
        tmp.m4[12]>>tmp.m4[13]>>tmp.m4[14]>>tmp.m4[15];
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="objrot" || buf=="objrotate" || buf=="objrotmat" || buf=="objrotatematrix")
    {
      UniformParam tmp;
      tmp.type=UniformParam::OBJROT;
      iss>>tmp.name;
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="objrottrans" || buf=="objrotatetranspose" || buf=="objrottransmat" || buf=="objrotatetransposematrix")
    {
      UniformParam tmp;
      tmp.type=UniformParam::OBJROTTRANS;
      iss>>tmp.name;
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="envrot" || buf=="envrotate" || buf=="envrotmat" || buf=="envrotatematrix")
    {
      UniformParam tmp;
      tmp.type=UniformParam::ENVROT;
      iss>>tmp.name;
      shader->UniformParamList.push_back(tmp);
    }
    else if (buf=="envrottrans" || buf=="envrotatetranspose" || buf=="envrottransmat" || buf=="envrotatetransposematrix")
    {
      UniformParam tmp;
      tmp.type=UniformParam::ENVROTTRANS;
      iss>>tmp.name;
      shader->UniformParamList.push_back(tmp);
    }
    else
    {
      printf("UNKNOWN PARAMETER: %s\n",buf.c_str());
      return false;
    }
  }
  return ShaderLoader::LoadShaderFile(VertexShaderFilename.c_str(),FragmentShaderFilename.c_str(),shader);
}

bool zObjectShader::Do(const string &cmd1, const vector<zParam*> &param, zParam *ret)
{
  Shader *obj=(Shader*)m_obj;
  zRenderScript *zrs=(zRenderScript*)m_zs;
  string cmd=ToLow_copy(cmd1);
  if (cmd=="begin")
  {
    obj->Begin();
    obj->SetUniforms(zrs->m_renderer);
  }
  else if (cmd=="end")
    obj->End();
  else if (cmd=="setuniforms")
    obj->SetUniforms(zrs->m_renderer);
  else if (cmd=="changeuniform1i")
  {
    string *str=zparam_cast<string*>(param[0]);
    if (!str) return false;
    double *d0=zparam_cast<double*>(param[1]);
    if (!d0) return false;
    obj->ChangeUniform(*str,(int)(*d0));
  }
  else if (cmd=="changeuniform1f")
  {
    string *str=zparam_cast<string*>(param[0]);
    if (!str) return false;
    double *d0=zparam_cast<double*>(param[1]);
    if (!d0) return false;
    obj->ChangeUniform(*str,(float)(*d0));
  }
  else return false;
  return true;
}

bool zObjectShader::IsTrue()
{
  return true;
}

string zObjectShader::ToString()
{
  return string("Shader");
}

}